package com.link.play.fit.ai.store

import android.app.Activity.RESULT_OK
import androidx.activity.ComponentActivity
import com.firebase.ui.auth.AuthUI
import com.firebase.ui.auth.FirebaseAuthUIActivityResultContract
import com.google.firebase.auth.ktx.auth
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.EventListener
import com.google.firebase.firestore.Filter
import com.google.firebase.firestore.ListenSource
import com.google.firebase.firestore.ListenerRegistration
import com.google.firebase.firestore.MetadataChanges
import com.google.firebase.firestore.QuerySnapshot
import com.google.firebase.firestore.SnapshotListenOptions
import com.google.firebase.firestore.Source
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.link.play.fit.ai.GlobalConfig
import com.link.play.fit.ai.R
import com.link.play.fit.ai.ext.launchContract
import com.link.play.fit.ai.kv.AuthCache
import com.link.play.fit.ai.utils.AppX
import java.util.UUID
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

/**
 *Create by SleepDog on 2025-03-26
 * firestore 存储与firebase登录相关
 */
object CloudStore {
    val db by lazy {
        Firebase.firestore
    }

    /**
     * User 登录的用户信息
     */
    inline val user get() = Firebase.auth.currentUser

    /**
     * Uid 用来做保存所用的key
     */
    inline val uid
        get() = if (isSignIn) user!!.uid else {
            AuthCache.uid.ifBlank {
                //没有登录的uid就只有用生成的，保存到本地
                val newUid = UUID.randomUUID().toString()
                AuthCache.uid = newUid
                newUid
            }
        }

    /**
     * 判断是否登录
     */
    inline val isSignIn get() = user != null


    const val DOC_LOG_WEIGHT = "logWeight"//记录体重
    const val DOC_USER_GUIDE = "docUserGuide"//引导页相关数据
    const val DOC_RECENTLY_LIST_DATA = "recentlyListData" //获取首页最近列表
    const val DOC_CALENDAR_STATUS_LIST_DATA = "calendarStatusListData" //日历状态
    const val DOC_CALENDAR_STATUS_LIST_DATA_KEY = "calendarStatusListDataKey" //日历状态key
    const val DOC_SAVE_FOOD_COLLECT_DATA = "saveFoodCollectListData" //收藏食物列表
    const val DOC_MEALS_TIME_LIST_DATA = "mealsTimeListData" //中餐推送时间列表
    const val DOC_FOOD_DATABASE_RECENTLY_DATA = "foodDatabaseRecentlyData" // 最近添加的食物, 不和首页的同步 要分开



    /**
     * 用谷歌账号登录
     *
     * @return Boolean 成功或者失败
     */
    suspend fun ComponentActivity.signInGoogle(): Boolean {
        if (isSignIn) return true
        val providers = arrayListOf(AuthUI.IdpConfig.GoogleBuilder().build())
        val signInIntent = AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .setTosAndPrivacyPolicyUrls(GlobalConfig.URL_USE, GlobalConfig.URL_PRIVACY)
            .setTheme(R.style.Base_Theme_FitAI)
            .build()
        val resultCode =
            launchContract(FirebaseAuthUIActivityResultContract(), signInIntent).resultCode
        return resultCode == RESULT_OK
    }

    /**
     * 保存或者更新数据
     * @param document 文档
     * @param data 数据
     */
    fun set(document: String, data: Any) {
        db.collection(uid).document(document).set(data)
    }

    /**
     * 保存到列表
     * @param document 文档
     * @param date 日期
     * @param key 列表的索引，一般是时间戳，用于查询和删除
     * @param data 保存的对象
     */
    fun addToList(document: String, date: String, key: String, data: Any) {
        db.collection(uid).document(document).collection(date).document(key)
            .set(data)
    }

    /**
     * 数据变化监听
     * @param document 文档
     * @param listener 回调监听
     * @return 取消监听需要用到的注册凭据
     */
    fun observe(document: String, listener: EventListener<DocumentSnapshot>): ListenerRegistration {
        return db.collection(uid).document(document).addSnapshotListener(
            SnapshotListenOptions.Builder()
                .setMetadataChanges(MetadataChanges.INCLUDE)
                .setSource(ListenSource.CACHE)
                .build(), listener
        )
    }

    /**
     * 列表数据变化监听
     * @param document 文档
     * @param date 日期
     * @param listener 回调监听
     * @return 取消监听需要用到的注册凭据
     */
    fun observeList(
        document: String,
        date: String,
        listener: EventListener<QuerySnapshot>
    ): ListenerRegistration {
        return db.collection(uid).document(document).collection(date)
            .addSnapshotListener(
                SnapshotListenOptions.Builder()
                    .setMetadataChanges(MetadataChanges.INCLUDE)
                    .setSource(ListenSource.CACHE)
                    .build(), listener
            )
    }

    /**
     * 获取存储的值
     * @param T  获取数据的类型
     * @param document  文档
     * @return  获取的数据
     */
    suspend inline fun <reified T> get(document: String): T? = suspendCoroutine { block ->
        db.collection(uid).document(document)
            .get(Source.CACHE)
            .addOnSuccessListener { data ->
                val realData = data.toObject(T::class.java)
                block.resume(realData)
            }.addOnFailureListener { _ ->
                block.resume(null)
            }
    }

    /**
     * 获取保存的列表
     * @param T 获取的列表中的类型
     * @param document 文档
     * @param date 日期
     * @return 获取的对应日期的列表数据
     */
    suspend inline fun <reified T> getList(document: String, date: String): List<T>? =
        suspendCoroutine { block ->
            db.collection(uid).document(document).collection(date)
                .get(Source.CACHE)
                .addOnSuccessListener { data ->
                    val realData = data.toObjects(T::class.java)
                    block.resume(realData)
                }.addOnFailureListener { _ ->
                    block.resume(null)
                }
        }

    suspend inline fun <reified T> getList(
        document: String,
        date: String,
        filter: Filter
    ): List<T>? =
        suspendCoroutine { block ->
            db.collection(uid).document(document).collection(date).where(filter)
                .get(Source.CACHE)
                .addOnSuccessListener { data ->
                    val realData = data.toObjects(T::class.java)
                    block.resume(realData)
                }.addOnFailureListener { _ ->
                    block.resume(null)
                }
        }

    /**
     * 获取列表数据中某个item
     * @param T 数据类型
     * @param document 文档
     * @param date 也是key
     * @param key 代表的key
     * @return 对象
     */
    suspend inline fun <reified T> getListItem(document: String, date: String, key: String): T? =
        suspendCoroutine { block ->
            db.collection(uid).document(document).collection(date).document(key)
                .get(Source.CACHE)
                .addOnSuccessListener { data ->
                    val realData = data.toObject(T::class.java)
                    block.resume(realData)
                }.addOnFailureListener { _ ->
                    block.resume(null)
                }
        }

    /**
     * 获得根据条件查询，最近一条的数据
     * @param T
     * @param document
     * @param date
     * @param filter
     * @return 最近一条的数据
     */
    suspend inline fun <reified T> getListItem(document: String, date: String, filter: Filter): T? =
        suspendCoroutine { block ->
            db.collection(uid).document(document).collection(date).where(filter)
                .get(Source.CACHE)
                .addOnSuccessListener { data ->
                    val realData = data.toObjects(T::class.java).lastOrNull()
                    block.resume(realData)
                }.addOnFailureListener { _ ->
                    block.resume(null)
                }
        }

    /**
     * 删除数据
     * @param document 文档
     */
    fun delete(document: String) {
        db.collection(uid).document(document).delete()
    }

    /**
     * 删除list中的item
     * @param document 对应的文档
     * @param date 日期
     * @param key  对应的删除的key
     */
    fun deleteList(document: String, date: String, key: String) {
        db.collection(uid).document(document).collection(date).document(key).delete()
    }

    /**
     * 删除账号
     */
    fun deleteAccount() {
        delete(DOC_USER_GUIDE)
        if (isSignIn) {
            AuthUI.getInstance().apply {
                delete(AppX.context)
            }
        }
        AuthCache.clear()
    }
}